﻿using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace SXFramWork.Core.MongoDB
{
    /// <summary>
    /// MongoDB服务
    /// </summary>
    public class MongoService: IMongoService
    {
        private readonly MongoClient _mongoClient;

        private IMongoDatabase _mongoDatabase;

        private string _mongoTable;
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="configuration"></param>
        public MongoService(IConfiguration configuration)
        {
            _mongoClient = new MongoClient(configuration["MongoDB:DefaultConnection"]);
            _mongoDatabase = _mongoClient.GetDatabase(configuration["MongoDB:DefaultDatabase"]);
            _mongoTable = configuration["MongoDB:DefaultTable"];
        }
        /// <summary>
        /// db
        /// </summary>
        /// <returns></returns>
        public IMongoDatabase GetDb()
        {
            return _mongoDatabase;
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public int Add<T>(T t,string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                _tb.InsertOne(t);
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 批量新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="mongoTable"></param>
        /// <returns>插入行数</returns>
        public int AddList<T>(IEnumerable<T> list, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                _tb.InsertMany(list);
                return list.Count();
            }
            catch
            {
                return 0;
            }
        }


        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public int Delete<T>(FilterDefinition<T> filter, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                _tb.DeleteMany(filter);
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public List<T> Query<T>(FilterDefinition<T> filter, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred); 
                return _tb.Find(filter).ToList();
            }
            catch(Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public List<T> Query<T>(Expression<Func<T, bool>> filter, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;
                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                return _tb.Find(filter).ToList();
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="update"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public int Update<T>(FilterDefinition<T> filter, UpdateDefinition<T> update, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                return _tb.UpdateMany(filter,update).ModifiedCount.To_Int();
            }
            catch
            {
                return -1;
            }
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public async Task<int> AddAsync<T>(T t, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;
                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                await _tb.InsertOneAsync(t);
                return 1;
            }
            catch
            {
                return 0;
            }
        }
        /// <summary>
        /// 计算总数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public long Count<T>(FilterDefinition<T> filter, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                return _tb.CountDocuments(filter);
            }
            catch (Exception ex)
            {
                return -1;
            }
        }
        /// <summary>
        /// 计算总数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public async Task<long> CountAsync<T>(FilterDefinition<T> filter, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);
                return await _tb.CountDocumentsAsync(filter);
            }
            catch (Exception ex)
            {
                return -1;
            }
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="field"></param>
        /// <param name="sort"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public List<T> FindListByPage<T>(FilterDefinition<T> filter, int pageIndex=1, int pageSize=20, string[] field = null, SortDefinition<T> sort = null, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);

                //不指定查询字段
                if (field == null || field.Length == 0)
                {
                    if (sort == null) return _tb.Find(filter).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToList();
                    //进行排序
                    return _tb.Find(filter).Sort(sort).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToList();
                }

                //指定查询字段
                var fieldList = new List<ProjectionDefinition<T>>();
                for (int i = 0; i < field.Length; i++)
                {
                    fieldList.Add(Builders<T>.Projection.Include(field[i].ToString()));
                }
                var projection = Builders<T>.Projection.Combine(fieldList);
                fieldList?.Clear();

                //不排序
                if (sort == null) return _tb.Find(filter).Project<T>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToList();

                //排序查询
                return _tb.Find(filter).Sort(sort).Project<T>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToList();

            }
            catch (Exception ex)
            {
                return null;
            }
        }
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="field"></param>
        /// <param name="sort"></param>
        /// <param name="mongoTable"></param>
        /// <returns></returns>
        public async Task<List<T>> FindListByPageAsync<T>(FilterDefinition<T> filter, int pageIndex=1, int pageSize=20, string[] field = null, SortDefinition<T> sort = null, string mongoTable = null)
        {
            try
            {
                if (!string.IsNullOrEmpty(mongoTable))
                    _mongoTable = mongoTable;

                var _tb = _mongoDatabase.GetCollection<T>(_mongoTable).WithReadPreference(ReadPreference.PrimaryPreferred);

                //不指定查询字段
                if (field == null || field.Length == 0)
                {
                    if (sort == null) return await _tb.Find(filter).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                    //进行排序
                    return await _tb.Find(filter).Sort(sort).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
                }

                //指定查询字段
                var fieldList = new List<ProjectionDefinition<T>>();
                for (int i = 0; i < field.Length; i++)
                {
                    fieldList.Add(Builders<T>.Projection.Include(field[i].ToString()));
                }
                var projection = Builders<T>.Projection.Combine(fieldList);
                fieldList?.Clear();

                //不排序
                if (sort == null) return await _tb.Find(filter).Project<T>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();

                //排序查询
                return await _tb.Find(filter).Sort(sort).Project<T>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
